Secure a ZK Application with Spring Security

From Documentation
Secure a ZK Application with Spring Security



Secure Your Application in Spring's Way

Spring Security is a widely-adopted framework. It can also work with ZK without problems. This doesn't even need zkspring-security. This page will show you how to do it. We assume you know the basics of Spring Boot and Spring Security. (You can read a Spring Security guide: Securing a Web Application ) So here we just mention those configurations specific to ZK framework.

The example code mentioned here only works for Spring Security 4/5.

ZK Spring Boot Starter

Spring encourages users to start with Spring Boot. So Please include zk spring boot starter, and it will automatically configure for you with most commonly-used settings.

Spring Boot Starter Security

Follow Securing a Web Application, we add the following elements:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>${springboot.version}</version>
        </dependency>

Spring Controller

For simplicity, we just register 2 URL mappings:

  • /login: login page
  • /secure/{page}: all secure pages
@SpringBootApplication
@Controller
public class Application {

    public static void main(String[] args) throws Throwable {
        SpringApplication.run(Application.class, args);
    }

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @GetMapping("/secure/{page}")
    public String secure(@PathVariable String page) {
        return "secure/" + page;
    }
}

Then put the corresponding zul under web/zul folder.

Zkspring-zul-path.png

Web Security Configuration

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    public static final String ZUL_FILES = "/zkau/web/**/*.zul";
    public static final String[] ZK_RESOURCES = {"/zkau/web/**/js/**", "/zkau/web/**/zul/css/**", "/zkau/web/**/img/**"};
    // allow desktop cleanup after logout or when reloading login page
    public static final String REMOVE_DESKTOP_REGEX = "/zkau\\?dtid=.*&cmd_0=rmDesktop&.*";

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
            .antMatchers(ZUL_FILES).denyAll() // block direct access to zul files
            .antMatchers(HttpMethod.GET, ZK_RESOURCES).permitAll() // allow zk resources
            .regexMatchers(HttpMethod.GET, REMOVE_DESKTOP_REGEX).permitAll() // allow desktop cleanup
            .requestMatchers(req -> "rmDesktop".equals(req.getParameter("cmd_0"))).permitAll() // allow desktop cleanup from ZATS
            .mvcMatchers("/","/login","/logout").permitAll()
            .mvcMatchers("/secure/**").hasRole("USER")
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login").defaultSuccessUrl("/secure/main")
            .and()
            .logout().logoutUrl("/logout").logoutSuccessUrl("/");
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        UserDetails user =
                User.withDefaultPasswordEncoder()
                        .username("user")
                        .password("password")
                        .roles("USER")
                        .build();

        return new InMemoryUserDetailsManager(user);
    }
}

Login Page

No matter how you design a login page, remember to enclose it with a <form> and the login URL you specify in the web security config.

    <n:form action="/login" method="POST">
        <grid width="450px">
            ...
                <row spans="2" align="right">
                    <hlayout>
                    <button type="reset" label="Reset" /> 
                    <button type="submit" label="Submit" />
                    </hlayout>
                </row>
          ...
        </grid>
    </n:form>

Download Demo Project

github - zkoss/zkspringboot - zkspringboot-security-demo

For an example without springboot (warfile with spring and zk-spring-security), please refer to: github - zkoss/zkspring - zkspringessentials/zkspringcoresec

Debug

Enable debug log in application.properties like logging.level.org.springframework.security.web=DEBUG if you use spring-boot.

For log4j, you can set log4j.category.org.springframework.security.web=TRACE

Check what spring security does internally for a request in the log like:

2022-11-29 09:29:25 [TRACE] FilterChainProxy:245 - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/login.zul*'], Filters=[]] (1/2)
2022-11-29 09:29:25 [TRACE] FilterChainProxy:245 - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@5534e6f1, org.springframework.security.web.context.SecurityContextHolderFilter@4c6fc3e7, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@aa8dce8, org.springframework.security.web.authentication.logout.LogoutFilter@6ad112de, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@18a0721b, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2ae2fa13, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@66e12c3b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@44485db, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1f6f0fe2, org.springframework.security.web.access.ExceptionTranslationFilter@22604c7e, org.springframework.security.web.access.intercept.AuthorizationFilter@4d8f2cfd]] (2/2)
2022-11-29 09:29:25 [TRACE] FilterChainProxy:245 - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@5534e6f1, org.springframework.security.web.context.SecurityContextHolderFilter@4c6fc3e7, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@aa8dce8, org.springframework.security.web.authentication.logout.LogoutFilter@6ad112de, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@18a0721b, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2ae2fa13, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@66e12c3b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@44485db, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1f6f0fe2, org.springframework.security.web.access.ExceptionTranslationFilter@22604c7e, org.springframework.security.web.access.intercept.AuthorizationFilter@4d8f2cfd]] (2/2)
2022-11-29 09:29:25 [DEBUG] FilterChainProxy:223 - Securing POST /zkau
2022-11-29 09:29:25 [DEBUG] FilterChainProxy:223 - Securing GET /index.zul

Reference



Last Update : 2022/12/20

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.